package com.bjc.platform.dao.impl;

import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import com.bjc.platform.dao.GenericDao;

@Repository
public class GenericDaoImpl implements GenericDao {

	@Autowired
	private EntityManager entityManager;

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	/**
	 * {@inheritDoc}
	 */
	public List<?> queryBySql(String sql, Map<String, Object> params,
			Pageable pager) {

		Query query = entityManager.createNativeQuery(sql);
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}

		List<?> result = query.getResultList();
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public List<?> queryBySql(String sql, Object[] params, Pageable pager) {

		Query query = entityManager.createNativeQuery(sql);
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}

		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}

		List<?> result = query.getResultList();
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public List<?> queryByJpql(String jpql, Map<String, Object> params,
			Pageable pager) {

		Query query = entityManager.createQuery(jpql);
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}

		return query.getResultList();
	}

	/**
	 * {@inheritDoc}
	 */
	public List<?> queryByJpql(String jpql, Object[] params, Pageable pager) {

		Query query = entityManager.createQuery(jpql);
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}

		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}

		List<?> result = query.getResultList();
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public long countBySql(String sql, Map<String, Object> params) {

		String s = "select count(*) from (" + sql + ") t ";
		Query query = entityManager.createNativeQuery(s);

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}
		
		BigInteger count = new BigInteger(query.getSingleResult() + "");

		return count.longValue();
	}

	/**
	 * {@inheritDoc}
	 */
	public long countBySql(String sql, Object[] params) {

		String s = "select count(*) num from (" + sql + ") t ";
		Query query = entityManager.createNativeQuery(s);

		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}

		BigInteger count = new BigInteger(query.getSingleResult() + "");

		return count.longValue();
	}

	/**
	 * {@inheritDoc}
	 */
	public long countByJpql(String jpql, Map<String, Object> params) {

		jpql = jpql.trim();
		String s = jpql.toLowerCase();
		int pos = s.indexOf("from");
		String ql = "select count(*) " + jpql.substring(pos);

		Query query = entityManager.createQuery(ql);

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}

		return (Long) query.getSingleResult();
	}

	/**
	 * {@inheritDoc}
	 */
	public long countByJpql(String jpql, Object[] params) {

		// String s = "select count(t) from (" + jpql + ") t ";
		jpql = jpql.trim();
		String s = jpql.toLowerCase();
		int pos = s.indexOf("from");
		String ql = "select count(*) " + jpql.substring(pos);

		Query query = entityManager.createQuery(ql);

		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}

		return (Long) query.getSingleResult();
	}

	@Override
	public void executeSql(String sql, Object[] objects) {
		if (sql != null) {
			Query query = entityManager.createNativeQuery(sql);
			if (objects != null) {
				for (int i = 0; i < objects.length; i++) {
					query.setParameter(i + 1, objects[i]);
				}
			}
			query.executeUpdate();
		}

	}

	@Override
	public List<Map<String, Object>> queryBySqlToMap(String sql, Object[] params) {
		Query query = entityManager.createNativeQuery(sql);
		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}
		query.unwrap(SQLQuery.class).setResultTransformer(
				Transformers.ALIAS_TO_ENTITY_MAP);
		return query.getResultList();
	}
	
	@Override
	public List<Map<String, Object>> queryBySqlToMap(String sql, Object[] params,Pageable pager) {
		Query query = entityManager.createNativeQuery(sql);
		
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}
		
		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}
		query.unwrap(SQLQuery.class).setResultTransformer(
				Transformers.ALIAS_TO_ENTITY_MAP);
		return query.getResultList();
	}

	@Override
	public List<Map<String, Object>> queryBySqlToMap(String sql, Map<String, Object> params) {
		Query query = entityManager.createNativeQuery(sql);

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}
		query.unwrap(SQLQuery.class).setResultTransformer(
				Transformers.ALIAS_TO_ENTITY_MAP);
		
		return query.getResultList();
	}
	

	@Override
	public List<Map<String, Object>> queryBySqlToMap(String sql,Map<String, Object> params,Pageable pager) {
		Query query = entityManager.createNativeQuery(sql);
		
		if (pager != null) {
			query.setFirstResult(pager.getOffset());
			query.setMaxResults(pager.getPageSize());
		}
		

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}
		query.unwrap(SQLQuery.class).setResultTransformer(
				Transformers.ALIAS_TO_ENTITY_MAP);
		
		return query.getResultList();
	}

	@Override
	public List<Object> queryBySql(String sql,Object[] params) {
		Query query = entityManager.createNativeQuery(sql);
		
		if (params != null && params.length > 0) {
			for (int i = 1; i <= params.length; i++) {
				query.setParameter(i, params[i - 1]);
			}
		}
		return query.getResultList();
	}
	
	@Override
	public Object queryOneBySql(String sql, Map<String, Object> params){
		Query query = entityManager.createNativeQuery(sql);

		if (params != null && params.size() > 0) {
			for (Entry<String, Object> entry : params.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				query.setParameter(name, value);
			}
		}
		List list = query.getResultList();
		if(list!=null && list.size()>0){
			return list.get(0);
		}
		return null;
	}
}
